using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

using System.IO;
using Microsoft.Xna.Framework.Content.Pipeline;
using Microsoft.Xna.Framework.Content.Pipeline.Graphics;
using Microsoft.Xna.Framework.Content.Pipeline.Processors;

namespace WindowsGameLibrary1 {
    [ContentProcessor]
    public class TerrainProcessor : ContentProcessor<Texture2DContent, ModelContent> {
        const float terrainScale = 3;
        const float terrainBumpiness = 64;
        const float texCoordScale = 0.1f;
        const string terrainTexture = "rocks.bmp";

        public override ModelContent Process(Texture2DContent input,
                                             ContentProcessorContext context) {
            MeshBuilder builder = MeshBuilder.StartMesh("terrain");

            input.ConvertBitmapType(typeof(PixelBitmapContent<float>));

            PixelBitmapContent<float> heightfield;
            heightfield = (PixelBitmapContent<float>)input.Mipmaps[0];

            for (int y = 0; y < heightfield.Height; y++) {
                for (int x = 0; x < heightfield.Width; x++) {
                    Vector3 position;

                    position.X = (x - heightfield.Width / 2) * terrainScale;
                    position.Z = (y - heightfield.Height / 2) * terrainScale;

                    position.Y = (heightfield.GetPixel(x, y) - 1) * terrainBumpiness;

                    builder.CreatePosition(position);
                }
            }

            BasicMaterialContent material = new BasicMaterialContent();

            string directory = Path.GetDirectoryName(input.Identity.SourceFilename);
            string texture = Path.Combine(directory, terrainTexture);

            material.Texture = new ExternalReference<TextureContent>(texture);

            builder.SetMaterial(material);

            int texCoordId = builder.CreateVertexChannel<Vector2>(
                                            VertexChannelNames.TextureCoordinate(0));

            for (int y = 0; y < heightfield.Height - 1; y++) {
                for (int x = 0; x < heightfield.Width - 1; x++) {
                    AddVertex(builder, texCoordId, heightfield.Width, x, y);
                    AddVertex(builder, texCoordId, heightfield.Width, x + 1, y);
                    AddVertex(builder, texCoordId, heightfield.Width, x + 1, y + 1);

                    AddVertex(builder, texCoordId, heightfield.Width, x, y);
                    AddVertex(builder, texCoordId, heightfield.Width, x + 1, y + 1);
                    AddVertex(builder, texCoordId, heightfield.Width, x, y + 1);
                }
            }

            MeshContent terrainMesh = builder.FinishMesh();

            return context.Convert<MeshContent, ModelContent>(terrainMesh,
                                                              "ModelProcessor");
        }
        static void AddVertex(MeshBuilder builder, int texCoordId, int w, int x, int y) {
            builder.SetVertexChannelData(texCoordId, new Vector2(x, y) * texCoordScale);
            builder.AddTriangleVertex(x + y * w);
        }

    }
}
